<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Tests XPConnect Wrappers</title>
    <script type="text/javascript" src="/MochiKit/packed.js"></script>
    <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
    <script class="testbody" type="text/javascript;version=1.7">
    ok(window instanceof Object, "window is instanceof Object");

    location.foopy = 3;

    var xow_answer = [];
    for (let i in location)
        xow_answer.push(i);

    var xpcnw_answer = [];
    var xpcnw = new XPCNativeWrapper(location);
    xpcnw.barpy = 4;
    for (let i in xpcnw)
        xpcnw_answer.push(i);

    var expected = [
        "hash",
        "host",
        "hostname",
        "href",
        "pathname",
        "port",
        "protocol",
        "search",
        "reload",
        "replace",
        "assign",
        "foopy"
    ];

    var xpcnw_expected = expected.slice(0, expected.length - 1);
    xpcnw_expected.push("barpy");

    is(xow_answer.sort().toString(),
       expected.sort().toString(),
       'enumeration over XOWs walks the prototype chain');

    is(xpcnw_answer.sort().toString(),
       xpcnw_expected.sort().toString(),
       'enumeration over XPCNWs walks the prototype chain');

    var for_each_expected = [];
    for each (let i in new XPCNativeWrapper(location))
        for_each_expected.push(typeof i);

    var for_each_answer = [];
    for each (let i in Iterator(new XPCNativeWrapper(location)))
        for_each_answer.push(typeof i);

    is(for_each_answer.sort().toString(),
       for_each_expected.sort().toString(),
       'wrapper iterators are properly iterators');

    let sjow_answer = [];
    let (obj = { a: 3, next:1 }) {
        for (let i in XPCSafeJSObjectWrapper({ __proto__: obj}))
            sjow_answer.push(i);
        is(sjow_answer.sort().toString(), ['a', 'next'].sort().toString(),
           'enumeration over SJOWs walks the prototype chain');
    }

    sjow_answer = [];
    for (let i in XPCSafeJSObjectWrapper(location))
        sjow_answer.push(i);

    is(sjow_answer.sort().toString(),
       expected.sort().toString(),
       'enumeration over SJOWs walks the prototype chain and works over XOWs');

    for (let i in XPCSafeJSObjectWrapper({ 0: 0, "hi": "there" })) {
        is(typeof i, "string", "enumeration on wrappers only returns strings");
    }

    ok(!(new XPCSafeJSObjectWrapper({}) == new XPCSafeJSObjectWrapper({})),
       'SJOWs equality hook returns false correctly');

    let (obj = {}) {
        ok(new XPCSafeJSObjectWrapper(obj) == new XPCSafeJSObjectWrapper(obj),
           'SJOWs equality hook returns true correctly');
    }

    ok(new XPCSafeJSObjectWrapper(window) == new XPCNativeWrapper(window),
       'SJOWs equality hook returns true correctly against XPCNW');
    ok(new XPCSafeJSObjectWrapper(window) == window,
       'SJOWs equality hook returns true correctly against XOW');

    is(typeof(new XPCSafeJSObjectWrapper(function(){})), 'function',
       'SJOWs look like functions when they wrap functions');
    is(typeof(new XPCSafeJSObjectWrapper({})), 'object',
       'SJOWs look like objects when they wrap objects');

    var origProto = window.__proto__;
    try {
        window.__proto__ = window;
        ok(false, 'cyclic proto value allowed');
        window.__proto__ = origProto;
    } catch (e) {
        is(e.toString(),
           'TypeError: cyclic __proto__ value',
           'throw the right exception for a cyclic proto');
        is(window.__proto__, origProto, 'reset __proto__ after a cyclic proto');
    }

    try {
        is('PASS', window.eval("'PASS'"), 'window.eval throws an exception');
    } catch (e) {
        ok(false, 'window.eval does not throw an exception');
    }

    try {
        new XPCNativeWrapper("");
        ok(false, "How did we construct a wrapper around a primitive?");
    } catch (e) {
        ok(true, "Unable to new XPCNativeWrapper(primitive)");
    }

    try {
        is(XPCNativeWrapper(""), "", "XPCNativeWrapper as a function allows primitives");
    } catch (e) {
        ok(false, "Unable to wrap a primitive, even without 'new'");
    }

    // Some tests for SJOWs too.
    is(new XPCSafeJSObjectWrapper(document.body) === document.body, true,
       "triple equals ignores wrappers");
    is(XPCSafeJSObjectWrapper.prototype + '',
       "[object XPCSafeJSObjectWrapper]",
       "able to convert XPCSafeJSObjectWrapper.prototype to string");

    XPCNativeWrapper.prototype = {};
    let (w = new XPCNativeWrapper(window)) {
        ok(window.location, "able to set XPCNativeWrapper.prototype and do stuff with it");
    }

    is(new XPCNativeWrapper(window, Window).closed, false,
       "able to wrap a window in a window XPCNativeWrapper");
    try {
        new XPCNativeWrapper(document, Window);
        ok(false, "Able to wrap a document in a Window XPCNativeWrapper?")
    } catch (e) {
        ok(/ILLEGAL_VALUE/(e), "not able to wrap a document in a Window XPCNativeWrapper");
    }

    let (w = new XPCNativeWrapper(window)) {
        w.foopybar = 5;
        ok(!("foopybar" in window), "XPCNativeWrappers allow expandos through");
        is(w.foopybar, 5, "can set expandos on XPCNativeWrappers, though");

        ok(delete w.foopybar, "deleting properties returns true correctly");
        ok(!("foopybar" in w), "Can delete properties from XPCNativeWrappers");

        is(w.window, window, "w.window exists and is the window");
        ok(delete w.window, "can delete builtin properties");
        is(w.window, window, "w.window is automatically recreated");

        window.foopy = 5;
        ok(delete w.foopy, "delete returns true");
        is(window.foopy, 5, "delete doesn't delete underlying properties");
        ok(delete window.foopy, "can delete window.foopy");
        ok(!("foopy" in window), "foopy is no longer in window");
    }

    try {
        is((function(x) { return x+1; }).apply(this,
                                               XPCSafeJSObjectWrapper([1])),
           2, "able to call apply with an XPCSafeJSObjectWrapped array");
    } catch (e) {
        ok(false,
           "Unable to call apply() with a XPCSafeJSObjectWrapped array");
    }

    try {
        window.__proto__ = null;
        is(window.__proto__, null,
           "allowed to update window.__proto__ to null");
    } catch (e) {
        ok(false, "some crazy exception was thrown");
    }

    try {
        new XPCSafeJSObjectWrapped(<x />).foo;
        ok(false, "Allowed to wrap E4X in SJOWs?");
    } catch (e) {
    }
    </script>
</body>
</html>
